package com.pub.stripe.service.impl;

import com.google.gson.JsonSyntaxException;
import com.pub.stripe.model.StripeConstant;
import com.pub.stripe.service.CallbackService;
import com.stripe.exception.SignatureVerificationException;
import com.stripe.model.*;
import com.stripe.net.Webhook;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.stream.Collectors;

@Slf4j
@Service
public class CallbackServiceImpl implements CallbackService {
    @Value("${stripe.webhookSecret}")
    private String webhookSecret;  //webhookSecret配置在Webhook秘钥签名中
    @Override
    public Object webhook(HttpServletRequest request, HttpServletResponse response) {
        InputStream inputStream = null;
        ByteArrayOutputStream output = null;
        try {
            //获取请求体的参数
            inputStream = request.getInputStream();
            output = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024*4];
            int n;
            while (-1 != (n = inputStream.read(buffer))) {
                output.write(buffer, 0, n);
            }
            byte[] bytes = output.toByteArray();
            String eventPayload = new String(bytes, "UTF-8");
            System.out.println("获取请求体的参数：" + eventPayload);
            //获取请求头签名
            String sigHeader = request.getHeader("Stripe-Signature");
            System.out.println("获取请求头的签名：" + sigHeader);
            Event event;
            try {
                event = Webhook.constructEvent(eventPayload,sigHeader,webhookSecret);  //调用webhook进行验签
            } catch (JsonSyntaxException e) {
                log.error("参数格式有误，解析失败：",e);
                response.setStatus(400);
                return "";
            }catch (SignatureVerificationException e) {
                log.error("参数被篡改，验签失败：",e);
                response.setStatus(400);
                return "";
            }
            EventDataObjectDeserializer dataObjectDeserializer = event.getDataObjectDeserializer();
            StripeObject stripeObject;
            if (dataObjectDeserializer.getObject().isPresent()) {  //如何数据为空
                stripeObject = dataObjectDeserializer.getObject().get();
            } else {
                //一般是网络或者Stripe引起的数据丢失
                response.setStatus(400);
                return "";
            }

            // 获取支付状态
            // Stripe的Webhooks中配置回调的时候同时指定了多种事件侦听，这些事件将被记录下来
            switch (event.getType()) {
                case StripeConstant.PAY_STRIPE_STATUS_CALL_BACK_SUCCESSED:
                    //支付成功
                    PaymentIntent paymentIntent = (PaymentIntent) stripeObject;
                    System.out.println("chargeId:" + paymentIntent.getLatestCharge());
                    String chargeId = paymentIntent.getLatestCharge();  //退款方式2：回调保存该退款编号用于退款，
                    break;
                case StripeConstant.PAY_STRIPE_STATUS_CALL_BACK_ATTACHED:
                    PaymentMethod paymentMethod = (PaymentMethod) stripeObject;
                    break;
                case StripeConstant.PAY_STRIPE_STATUS_CALL_BACK_CANCELED:
                    log.warn("取消订单");
                    break;
                case StripeConstant.PAY_STRIPE_STATUS_CALL_BACK_FAILED:
                    log.warn("支付失败");
                    break;
                default:
                    System.out.println("Unhandled event type: " + event.getType());
            }
            response.setStatus(200);  //处理无异常，返回
        }catch (Exception e){
            log.error("webhook异步通知解析异常：",e);
            response.setStatus(400);
            return "";
        }finally {
            try {
                if (inputStream != null){
                    inputStream.close();
                }
                if (output != null){
                    output.close();
                }
            }catch (Exception e){
                log.error("流关闭异常");
            }
        }
        return "";
    }
}
